﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace xycn.common
{
    /// <summary>
    /// DataExtension
    /// </summary>	
    public static class DataTableExtension
    {
        /// <summary>
        /// ToList
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <param name="reader">reader</param>
        /// <returns>T</returns>
        public static List<T> ToList<T>(this IDataReader reader) where T : class, new()
        {
            var result = new List<T>();

            DataTable dt = reader.GetSchemaTable();
            try
            {
                while (reader.Read())
                {
                    var t = new T();

                    if (dt != null)
                    {
                        foreach (DataRow dr in dt.Rows)
                        {
                            // 当前列名&属性名
                            string columnName = dr[0].ToString();
                            PropertyInfo pro = typeof(T).GetProperty(columnName);

                            if (pro == null)
                            {
                                continue;
                            }

                            if (!pro.CanWrite)
                            {
                                continue;
                            }

                            pro.SetValue(t, ConvertExtension.ConvertHelper(reader[columnName], pro.PropertyType), null);
                        }
                    }

                    result.Add(t);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (!reader.IsClosed)
                {
                    reader.Dispose();
                    reader.Close();
                }
            }

            return result;
        }

        /// <summary>
        /// ToList
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <param name="dt">dt</param>
        /// <returns>T</returns>
        public static List<T> ToList<T>(this DataTable dt) where T : class, new()
        {
            var result = new List<T>();
            foreach (DataRow dr in dt.Rows)
            {
                var t = new T();
                try
                {
                    foreach (DataColumn column in dt.Columns)
                    {
                        // 当前列名&属性名
                        string columnName = column.ColumnName;
                        PropertyInfo pro = typeof(T).GetProperty(columnName);

                        if (pro == null)
                        {
                            continue;
                        }

                        if (!pro.CanWrite)
                        {
                            continue;
                        }

                        pro.SetValue(t, ConvertExtension.ConvertHelper(dr[columnName], pro.PropertyType), null);
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }

                result.Add(t);
            }

            return result;
        }

        /// <summary>
        /// ToList
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <param name="ds">ds</param>
        /// <returns>T</returns>
        public static List<T> ToList<T>(this DataSet ds) where T : class, new()
        {
            return ds.Tables[0].ToList<T>();
        }

        /// <summary>
        /// ToList
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <param name="ds">ds</param>
        /// <param name="dataTableIndex">dataTableIndex</param>
        /// <returns>T</returns>
        public static List<T> ToList<T>(this DataSet ds, int dataTableIndex) where T : class, new()
        {
            return ds.Tables[dataTableIndex].ToList<T>();
        }

        /// <summary>
        /// ToModel
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <param name="reader">reader</param>
        /// <returns>T</returns>
        public static T ToModel<T>(this IDataReader reader) where T : class, new()
        {
            var t = new T();
            DataTable dt = reader.GetSchemaTable();
            try
            {
                while (reader.Read())
                {
                    if (dt != null)
                    {
                        foreach (DataRow dr in dt.Rows)
                        {
                            // 当前列名&属性名
                            string columnName = dr[0].ToString();
                            PropertyInfo pro = typeof(T).GetProperty(columnName);

                            if (pro == null)
                            {
                                continue;
                            }

                            if (!pro.CanWrite)
                            {
                                continue;
                            }

                            pro.SetValue(t, ConvertExtension.ConvertHelper(reader[columnName], pro.PropertyType), null);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (!reader.IsClosed)
                {
                    reader.Dispose();
                    reader.Close();
                }
            }

            return t;
        }

        /// <summary>
        /// ToModel
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <param name="dt">dt</param>
        /// <returns>T</returns>
        public static T ToModel<T>(this DataTable dt) where T : class, new()
        {
            var t = new T();
            if (dt.Rows.Count <= 0)
            {
                return t;
            }

            try
            {
                foreach (DataColumn column in dt.Columns)
                {
                    // 当前列名&属性名
                    string columnName = column.ColumnName;
                    PropertyInfo pro = typeof(T).GetProperty(columnName);
                    if (pro == null)
                    {
                        continue;
                    }

                    if (!pro.CanWrite)
                    {
                        continue;
                    }

                    pro.SetValue(t, ConvertExtension.ConvertHelper(dt.Rows[0][columnName], pro.PropertyType), null);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return t;
        }

        /// <summary>
        /// ToModel
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <param name="ds">ds</param>
        /// <param name="dataTableIndex">dataTableIndex</param>
        /// <returns>T</returns>
        public static T ToModel<T>(this DataSet ds, int dataTableIndex = 0) where T : class, new()
        {
            return ds.Tables[0].ToModel<T>();
        }


        /// <summary>
        /// DataTable 先转成 List字典,mvc自动序列号
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <param name="dt">dt</param>
        /// <returns>T</returns>
        public static List<Dictionary<string, object>> ToDictionary(this DataTable dt)
        {
            var lstdic = new List<Dictionary<string, object>>();

            foreach (DataRow dr in dt.Rows)
            {
                var dic = new Dictionary<string, object>();
                foreach (DataColumn item in dt.Columns)
                {
                    dic.Add(item.ColumnName, ConvertValueByType(item, dr[item]));
                }
                lstdic.Add(dic);
            }
            return lstdic;
        }

        /// <summary>
        /// DataTable 先转成 List字典,mvc自动序列号
        /// </summary>
        /// <param name="drow">The drow.</param>
        /// <returns>
        /// T
        /// </returns>
        public static Dictionary<string, object> ToDictionary(this DataRow drow)
        {
            var dic = new Dictionary<string, object>();
            if (drow == null || drow.Table == null)
            {
                return dic;
            }
            foreach (DataColumn item in drow.Table.Columns)
            {
                dic.Add(item.ColumnName, ConvertValueByType(item, drow[item]));
            }
            return dic;
        }

        /// <summary>
        /// DataTable 先转成 List字典,mvc自动序列号
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <param name="dt">dt</param>
        /// <returns>T</returns>
        public static List<Dictionary<string, object>> ToDictionaryWithKeyLower(this DataTable dt)
        {
            var lstdic = new List<Dictionary<string, object>>();

            foreach (DataRow dr in dt.Rows)
            {
                var dic = new Dictionary<string, object>();
                foreach (DataColumn item in dt.Columns)
                {
                    dic.Add(item.ColumnName.ToLower(), ConvertValueByType(item, dr[item]));
                }
                lstdic.Add(dic);
            }
            return lstdic;
        }

        /// <summary>
        /// DataTable的类型转换 主要处理时间
        /// </summary>
        /// <param name="item">The item.</param>
        /// <param name="obj">The object.</param>
        /// <returns></returns>
        public static object ConvertValueByType(DataColumn item, object obj)
        {
            if (obj.IsNull())
            {
                return null;
            }
            if (item.DataType.Name.ToLower() == "datetime" || item.DataType.Name.ToLower() == "mysqldatetime")
            {
                return Convert.ToDateTime(obj).ToString("yyyy-MM-dd HH:mm:ss");
            }
            else if (item.DataType.Name.ToLower() == "int32")
            {
                return Convert.ToInt32(obj);
            }
            else if (item.DataType.Name.ToLower() == "int64")
            {
                return Convert.ToInt64(obj);
            }
            return obj.ToString();
        }

        /// <summary>
        /// To the data table.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items">The items.</param>
        /// <returns></returns>
        public static DataTable ToDataTable<T>(List<T> items)
        {
            var tb = new DataTable(typeof(T).Name);

            PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

            foreach (PropertyInfo prop in props)
            {
                Type t = GetCoreType(prop.PropertyType);
                tb.Columns.Add(prop.Name, t);
            }

            foreach (T item in items)
            {
                var values = new object[props.Length];

                for (int i = 0; i < props.Length; i++)
                {
                    values[i] = props[i].GetValue(item, null);
                }

                tb.Rows.Add(values);
            }

            return tb;
        }

        /// <summary>
        /// Determines whether the specified t is nullable.
        /// </summary>
        /// <param name="t">The t.</param>
        /// <returns></returns>
        public static bool IsNullable(Type t)
        {
            return !t.IsValueType || (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>));
        }

        /// <summary>
        /// Gets the type of the core.
        /// </summary>
        /// <param name="t">The t.</param>
        /// <returns></returns>
        public static Type GetCoreType(Type t)
        {
            if (t != null && IsNullable(t))
            {
                if (!t.IsValueType)
                {
                    return t;
                }
                else
                {
                    return Nullable.GetUnderlyingType(t);
                }
            }
            else
            {
                return t;
            }
        }
    }
}
